package org.dromara.wms.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.web.core.BaseService;
import org.dromara.wms.domain.*;
import org.dromara.wms.mapper.WmsOrderTypeMapper;
import org.dromara.wms.mapper.WmsStockLogMapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.dromara.wms.mapper.WmsStockMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 库存数量Service业务层处理
 *
 * @author wenrui Su
 * @date 2024-05-03
 */
@RequiredArgsConstructor
@Service
public class WmsStockService extends BaseService {

    private final WmsStockMapper baseMapper;

    private final WmsStockLogMapper logMapper;

    /**
     * 查询库存数量
     */
    public WmsStock queryById(Long id){
        return baseMapper.selectById(id);
    }

  /**
   * 查询库存数量列表&产品表
   */
  public TableDataInfo<WmsStock> queryPageList(WmsStock bo, PageQuery pageQuery) {
    Page<WmsStock> result = baseMapper.queryPageList(pageQuery.build(),bo);
    return TableDataInfo.build(result);
  }

    /**
     * 查询库存数量列表
     */
    public List<WmsStock> queryList(WmsStock bo) {
        LambdaQueryWrapper<WmsStock> lqw = buildQueryWrapper(bo);
        return baseMapper.selectList(lqw);
    }

    private LambdaQueryWrapper<WmsStock> buildQueryWrapper(WmsStock bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<WmsStock> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getProductId() != null, WmsStock::getProductId, bo.getProductId());
        lqw.eq(StringUtils.isNotBlank(bo.getMeasureUnit()), WmsStock::getMeasureUnit, bo.getMeasureUnit());
        lqw.eq(StringUtils.isNotBlank(bo.getBatchCode()), WmsStock::getBatchCode, bo.getBatchCode());
        lqw.eq(bo.getWarehouseId() != null, WmsStock::getWarehouseId, bo.getWarehouseId());
        lqw.eq(bo.getAreaId() != null, WmsStock::getAreaId, bo.getAreaId());
        lqw.eq(bo.getSupplierId() != null, WmsStock::getSupplierId, bo.getSupplierId());
        lqw.eq(bo.getManufacturerId() != null, WmsStock::getManufacturerId, bo.getManufacturerId());
        lqw.eq(bo.getQuantity() != null, WmsStock::getQuantity, bo.getQuantity());
        lqw.eq(bo.getPurchasePrice() != null, WmsStock::getPurchasePrice, bo.getPurchasePrice());
        lqw.eq(bo.getExpireDate() != null, WmsStock::getExpireDate, bo.getExpireDate());
        return lqw;
    }

    /**
     * 新增库存数量
     */
    public Boolean insertByBo(WmsStock bo) {
        validEntityBeforeSave(bo);
        return baseMapper.insert(bo) > 0;
    }

    /**
     * 修改库存数量
     */
    public Boolean updateByBo(WmsStock bo) {
        validEntityBeforeSave(bo);
        return baseMapper.updateById(bo) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(WmsStock entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除库存数量
     */
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

  @Transactional(propagation = Propagation.REQUIRED)
  public R<Void> execOrder(WmsOrder orderVo) throws emptyException {
    R<Void> res = null;
    List<WmsOrderLine> line = orderVo.getLine();
    for (WmsOrderLine li : line){
      WmsStock stockVo = new WmsStock();
      stockVo.setProductId(li.getProductId());
      stockVo.setProductName(li.getProductName());
      stockVo.setWareName(orderVo.getWarehouseName());
      stockVo.setMeasureUnit(li.getMeasureUnit());
      stockVo.setWarehouseId(orderVo.getSelfWhId());
      stockVo.setBatchCode(li.getBatchCode());
      stockVo.setQuantity(li.getQuantity());
      stockVo.setSupplierId(orderVo.getPartnerId());
      stockVo.setPurchasePrice(li.getPrice());
      if (orderVo.getWmsType().equals("in")){
        res = this.stockIn(stockVo,orderVo);
      } else if (orderVo.getWmsType().equals("out")){
        res = this.stockOut(stockVo,orderVo);
      }
      if (R.isError(res)){
        return res;
      }
    }

    return res;
  }

  //仓库日志记录
  private void  insertWmsStockLog(WmsStock stockVo, WmsOrder orderVo, Double quantityBefore, String inOut){
    WmsStockLog stockLog = setWmsStockLog(stockVo, orderVo, quantityBefore, inOut);
    logMapper.insert(stockLog);
  }

  @NotNull
  private WmsStockLog setWmsStockLog(WmsStock stockVo, WmsOrder orderVo, Double quantityBefore, String inOut) {
    WmsStockLog stockLog = new WmsStockLog();
    stockLog.setProductId(stockVo.getProductId());
    stockLog.setMeasureUnit(stockVo.getMeasureUnit());
    stockLog.setBatchCode(stockVo.getBatchCode());
    stockLog.setOrderId(orderVo.getId());
    stockLog.setPrice(stockVo.getPrice());
    stockLog.setWarehouseId(stockVo.getWarehouseId());
    stockLog.setQuantityBefore(quantityBefore);
    if (Objects.equals(inOut, "in")){
      stockLog.setQuantityAfter(quantityBefore + stockVo.getQuantity());
    }else if(Objects.equals(inOut, "out")){
      stockLog.setQuantityAfter(quantityBefore - stockVo.getQuantity());
    }
    stockLog.setRemark(stockVo.getRemark());
    stockLog.setCreateTime(new Date());
    stockLog.setTypeId(orderVo.getTypeId());
    return stockLog;
  }


  /**
   * 修改库存数量
   */
  @Transactional(propagation = Propagation.REQUIRED)
  public R<Void> stockIn(WmsStock vo, WmsOrder wmsOrder) {
    R<Void> res = null;
    List<WmsStock> stockList = selectList(vo);
    double totalQuantity = stockList.stream()
      .mapToDouble(WmsStock::getQuantity)
      .sum();
    insertWmsStockLog(vo,wmsOrder,totalQuantity,"in");
    if (!stockList.isEmpty()){
      vo.setId(stockList.get(0).getId());
      res = toAjax(baseMapper.updateQuantity(vo));
    } else {
      res = toAjax(baseMapper.insert(vo));
    }
    return res;
  }

  @Transactional(propagation = Propagation.REQUIRED)
  public R<Void> stockIn(WmsStock vo) {
    R<Void> res = null;
    List<WmsStock> stockList = selectList(vo);
    if (!stockList.isEmpty()){
      vo.setId(stockList.get(0).getId());
      res = toAjax(baseMapper.updateQuantity(vo));
    } else {
      res = toAjax(baseMapper.insert(vo));
    }
    return res;
  }

  public static class emptyException extends RuntimeException {
    public emptyException(String message) {
      super(message);
    }
  }

  @Transactional(propagation = Propagation.REQUIRED)
  public R<Void> stockOut(WmsStock vo, WmsOrder wmsOrder) throws emptyException {
    List<WmsStock> stockList = selectList(vo);
    if (stockList.isEmpty()){
      throw new emptyException(vo.getWareName()+" 中暂无 "+vo.getProductName()+" 此产品，请核对后重试");
    }
    double totalQuantity = stockList.stream()
      .mapToDouble(WmsStock::getQuantity)
      .sum();
    insertWmsStockLog(vo,wmsOrder,totalQuantity,"out");
    Double num = vo.getQuantity();
    for (WmsStock stock : stockList){
      //num是要出库的物品数量
      //num减去当前批次物品数量，小于等于0，说明当前批次物品数量足够出库，大于0 说明不够出库,放入下个循环看能否出库
      Double quantityBefore = stock.getQuantity();
      if (num - stock.getQuantity() > 0){
        //当前库存不够，数量变负数，放入更新，自减归零
        stock.setQuantity(-stock.getQuantity());
      }else{
        //当前库存足够，num变负数，库存减去num
        stock.setQuantity(-num);
      }
      num -= quantityBefore;
      baseMapper.updateQuantity(stock);
      if (num <= 0) break;
    }
      if (num > 0){
        throw new emptyException(vo.getWareName()+" 中产品 "+vo.getProductName()+" 数量不足，请核对后重试");
      }
    return R.ok("更新成功");
  }

  @Transactional(propagation = Propagation.REQUIRED)
  public List<WmsTaskBom> stockOut(WmsStock vo, WmsOrder wmsOrder, String batchCode) throws emptyException {
    List<WmsTaskBom> wmsTaskBomList = new ArrayList<>();
    List<WmsStock> stockList = selectList(vo);
    if (stockList.isEmpty()){
      throw new emptyException(vo.getWareName() + " 中暂无 "+vo.getProductName()+" 此产品，请核对后重试");
    }
    double totalQuantity = stockList.stream()
      .mapToDouble(WmsStock::getQuantity)
      .sum();
    vo.setBatchCode(batchCode);
    insertWmsStockLog(vo,wmsOrder,totalQuantity,"out");
    Double num = vo.getQuantity();
    for (WmsStock stock : stockList){
      //num是要出库的物品数量
      //num减去当前批次物品数量，小于等于0，说明当前批次物品数量足够出库，大于0 说明不够出库,放入下个循环看能否出库
      Double quantityBefore = stock.getQuantity();
      if (num - stock.getQuantity() > 0){
        //当前库存不够，数量变负数，放入更新，自减归零
        stock.setQuantity(-stock.getQuantity());
      }else{
        //当前库存足够，num变负数，库存减去num
        stock.setQuantity(-num);
      }
      num -= quantityBefore;
      baseMapper.updateQuantity(stock);
        WmsTaskBom wmsTaskBom = new WmsTaskBom();
        wmsTaskBom.setBatchCode(stock.getBatchCode());
        wmsTaskBom.setProductId(stock.getProductId());
        wmsTaskBomList.add(wmsTaskBom);
      if (num <= 0) break;
    }
    if (num > 0){
      throw new emptyException(vo.getWareName()+" 中产品 "+vo.getProductName()+" 数量不足，请核对后重试");
    }
    return wmsTaskBomList;
  }

  public List<WmsStock> selectList(WmsStock vo) {
    LambdaQueryWrapper<WmsStock> lqw = Wrappers.lambdaQuery();
    lqw.eq(true, WmsStock::getWarehouseId, vo.getWarehouseId());
    lqw.eq(true, WmsStock::getProductId, vo.getProductId());
    lqw.eq(vo.getBatchCode() != null, WmsStock::getBatchCode, vo.getBatchCode());
    return baseMapper.selectList(lqw);
  }

  @Transactional(propagation = Propagation.REQUIRED)
  public void updateStock(WmsStock stockLine, WmsStockCheckLine line){
    stockLine.setMeasureUnit(line.getMeasureUnit());
    stockLine.setProductId(line.getProductId());
    stockLine.setQuantity(line.getCheckQuantity()-line.getBeforeQuantity());
    stockLine.setWarehouseId(line.getWarehouseId());
    stockLine.setBatchCode(line.getBatchCode());
    baseMapper.updateQuantity(stockLine);
  }
}
